﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Compiler_Phase_3
{
    public class Parser
    {
        #region FIELDS

        LexicalAnalyzer lexical; //Current token
        bool traceOn;  //En/disable trace comments
        Token currentToken; //current token being parsed.
        bool errorFound; //If an error is found
        int lineNumber;
        string line; //holds the data of a single line for output

        const int PLACEHOLDER = 0; //Return value for each non-term, TBReplaced

        #endregion

        public Parser(LexicalAnalyzer lex, bool trace)
        {
            lexical = lex;
            traceOn = trace;
            errorFound = false;
            line = "";
        }

        public void Test()
        {
            while (lexical.IsEnd() == false)
            {
                Constant();
                if (errorFound == true)
                {
                    lexical.GetNextToken();
                }
            }
        }
        private void ErrorMsg(string error)
        {
            Console.WriteLine("\nERROR: " + error);
        }
        private void Msg(string msg)
        {
            Console.WriteLine("\nMSG: " + msg);
        }
        private void Output()
        {
            if (traceOn == true) //Printing "VERBOSE"
            {
                if (lexical.GetLineNumber != lineNumber)
                {
                    lineNumber = lexical.GetLineNumber;
                    Console.WriteLine("\n" + lineNumber + "\t"  
                    + currentToken.Lexeme + lexical.GetSourceLine);
                }
                Console.WriteLine("\n TOKEN: " + currentToken.Lexeme + " " + 
                    " TOKEN CODE: " + currentToken.Mnemonic);
            }

        }
        private void UpdateOutput()
        {

        }
        /*--------------------------------------------------------------------|
         * IDENTIFIER:                                                        |
         * ------------------------------------------------------------------*/
        private int Identifier()
        {
            if (traceOn == true)
            {
                Msg("ENTERING 'IDENTIFIER'");
            }
            const int IDENT = 1; //Token Code for identifiers
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == IDENT)
            {
                lexical.GetNextToken();
            }
            else
            {
                ErrorMsg("Identifier expected but '" +
                    currentToken.Mnemonic + "' found.");
                errorFound = true;
            }
            if (traceOn == true)
            {
                Msg("EXITING 'IDENTIFIER'");
            }
            Output();
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * UNSIGNED INTEGER                                                   |
         * ------------------------------------------------------------------*/
        private int UnsignedInteger()
        {
            if (traceOn == true)
            {
                Msg("ENTERING 'UNSIGNED INTEGER'");
            }
            const int UNINT = 3; //Token code for integers
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == UNINT)
            {
                lexical.GetNextToken();
            }
            else
            {
                ErrorMsg("Unsigned Integer expected but '" +
                    currentToken.Mnemonic + "' found.");
                errorFound = true;
            }
            if (traceOn == true)
            {
                Msg("EXITING 'UNSIGNED INTEGER'");
            }
            Output();
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * UNSIGNED NUMBER                                                    |
         * ------------------------------------------------------------------*/
        private int UnsignedNumber()
        {
            if (traceOn == true)
            {
                Msg("ENTERING 'UNSIGNED NUMBER'");
            }
            UnsignedInteger();
            if (traceOn == true)
            {
                Msg("EXITING 'UNSIGNED NUMBER'");
            }
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * UNSIGNED CONSTANT                                                  |
         * ------------------------------------------------------------------*/
        private int UnsignedConstant()
        {
            if (traceOn == true)
            {
                Msg("ENTERING 'UNSIGNED CONSTANT'");
            }
            UnsignedNumber();
            if (traceOn == true)
            {
                Msg("EXITING 'UNSIGNED CONSTANT'");
            }
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * ADDOP                                                              |
         * ------------------------------------------------------------------*/
        private int AddOp()
        {
            if (traceOn == true)
            {
                Msg("ENTERING 'ADDOP'");
            }
            const int ADD = 10; //Token code for ADD
            const int MIN = 13; //Token code for MINUS
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == ADD || currentToken.TokenCode == MIN)
            {
                lexical.GetNextToken();
            }
            else
            {
                ErrorMsg("AddOp expected but '" +
                    currentToken.Mnemonic + "' found.");
                errorFound = true;
            }
            if (traceOn == true)
            {
                Msg("EXITING 'ADDOP'");
            }
            Output();
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * SIGN                                                               |
         * ------------------------------------------------------------------*/
        private int Sign()
        {
            if (traceOn == true)
            {
                Msg("ENTERING 'SIGN'");
            }
            const int ADD = 10; //Token code for ADD
            const int MIN = 13; //Token code for MINUS
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == ADD || currentToken.TokenCode == MIN)
            {
                lexical.GetNextToken();
            }
            else
            {
                ErrorMsg("SIGN expected but '" +
                    currentToken.Mnemonic + "' found.");
                errorFound = true;
            }
            if (traceOn == true)
            {
                Msg("EXITING 'SIGN'");
            }
            Output();
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * CONSTANT                                                           |
         * ------------------------------------------------------------------*/
        private int Constant()
        {
            if (traceOn == true)
            {
                Msg("ENTERING 'CONSTANT'");
            }
            Sign();
            UnsignedConstant();
            if (traceOn == true)
            {
                Msg("EXITING 'CONSTANT'");
            }
            return PLACEHOLDER;
        }
    }
}
